#ifndef BASE_WINPING_H_
#define BASE_WINPING_H_

#ifdef WIN32

#include "win32.h"
#include "ipaddress.h"

namespace base
{
	// This class wraps a Win32 API for doing ICMP pinging.  This API, unlike the
	// the normal socket APIs (as implemented on Win9x), will return an error if
	// an ICMP packet with the dont-fragment bit set is too large.  This means this
	// class can be used to detect the MTU to a given address.

	typedef struct ip_option_information
	{
		UCHAR	Ttl;			// Time To Live
		UCHAR	Tos;			// Time Of Service
		UCHAR	Flags;			// IP header flags
		UCHAR	OptionsSize;	// Size in bytes of options data
		PUCHAR	OptionsData;	// Pointer to options data
	} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;

	typedef HANDLE (WINAPI *PIcmpCreateFile)();

	typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle);

	typedef HANDLE (WINAPI *PIcmp6CreateFile)();

	typedef BOOL (WINAPI *PIcmp6CloseHandle)(HANDLE icmp_handle);

	typedef DWORD (WINAPI *PIcmpSendEcho)(
		HANDLE                   IcmpHandle,
		ULONG                    DestinationAddress,
		LPVOID                   RequestData,
		WORD                     RequestSize,
		PIP_OPTION_INFORMATION   RequestOptions,
		LPVOID                   ReplyBuffer,
		DWORD                    ReplySize,
		DWORD                    Timeout);

	typedef DWORD (WINAPI *PIcmp6SendEcho2)(
		HANDLE IcmpHandle,
		HANDLE Event,
		FARPROC ApcRoutine,
		PVOID ApcContext,
	struct sockaddr_in6 *SourceAddress,
	struct sockaddr_in6 *DestinationAddress,
		LPVOID RequestData,
		WORD RequestSize,
		PIP_OPTION_INFORMATION RequestOptions,
		LPVOID ReplyBuffer,
		DWORD ReplySize,
		DWORD Timeout
		);

	class WinPing
	{
	public:
		WinPing();
		~WinPing();

		// Determines whether the class was initialized correctly.
		bool IsValid() { return valid_; }

		// Attempts to send a ping with the given parameters.
		enum PingResult
		{ 
			PING_FAIL, 
			PING_INVALID_PARAMS,
			PING_TOO_LARGE,
			PING_TIMEOUT,
			PING_SUCCESS
		};

		PingResult Ping(IPAddress ip, uint32 data_size, uint32 timeout_millis,
			uint8 ttl, bool allow_fragments);

	private:
		HMODULE	dll_;
		HANDLE hping_;
		HANDLE hping6_;
		PIcmpCreateFile create_;
		PIcmpCloseHandle close_;
		PIcmpSendEcho send_;
		PIcmp6CreateFile create6_;
		PIcmp6SendEcho2 send6_;
		char* data_;
		uint32 dlen_;
		char* reply_;
		uint32 rlen_;
		bool valid_;
	};
}

#endif

#endif	// BASE_WINPING_H_